/*
 * Lenovo Group
 * Copyright (c) 2015-2016 All Rights Reserved.
 * 
 * Project Name:assign-tracer
 * Create Time: 2016年1月28日 下午12:00:53
 */
package com.lenovo.lmrp.server.assigntracer.spi;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import javax.inject.Inject;
import javax.ws.rs.Consumes;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.lenovo.lmrp.api.assigntrace.ITraceTicket;
import com.lenovo.lmrp.api.constant.AppStatus;
import com.lenovo.lmrp.api.constant.EvaluateResults;
import com.lenovo.lmrp.api.constant.QueryEntity;
import com.lenovo.lmrp.api.constant.TicketAction;
import com.lenovo.lmrp.api.constant.TicketPolicy;
import com.lenovo.lmrp.api.constant.TicketPriority;
import com.lenovo.lmrp.api.constant.TicketStatus;
import com.lenovo.lmrp.api.constant.TicketType;
import com.lenovo.lmrp.api.model.RestResponse;
import com.lenovo.lmrp.api.model.entity.ProcessActivityPO;
import com.lenovo.lmrp.api.model.entity.ProjectPO;
import com.lenovo.lmrp.api.model.entity.TicketPO;
import com.lenovo.lmrp.api.model.entity.TicketProcessPO;
import com.lenovo.lmrp.api.model.entity.TicketSLAPO;
import com.lenovo.lmrp.api.model.view.AttachmentVO;
import com.lenovo.lmrp.api.model.view.ChangedTicketVO;
import com.lenovo.lmrp.api.model.view.SearchListFilter;
import com.lenovo.lmrp.api.model.view.TicketCost;
import com.lenovo.lmrp.api.model.view.TicketStatistics;
import com.lenovo.lmrp.api.model.view.TicketTotalVO;
import com.lenovo.lmrp.api.model.view.TicketVO;
import com.lenovo.lmrp.server.assigntracer.domain.service.QuerySelector;
import com.lenovo.lmrp.server.assigntracer.domain.ticket.ITicketRepository;
import com.lenovo.lmrp.server.assigntracer.domain.workflow.TicketProcessBO;
import com.lenovo.lmrp.server.assigntracer.repository.BaseInfoRepository;
import com.lenovo.lmrp.server.assigntracer.repository.WorkflowRepository;
import com.lenovo.sdc.framework.annotation.RestService;
import com.lenovo.sdc.framework.dao.ADaoFactory;
import com.lenovo.sdc.framework.dao.ICommonDAO;
import com.lenovo.sdc.framework.util.AttributeBean;
import com.lenovo.sdc.framework.util.CommonUtil;
import com.lenovo.sdc.framework.util.exception.ErrorCode;
import com.lenovo.sdc.framework.util.exception.TraceableException;

/**
 * @author zhangzhenga
 *
 */
@RestService
@Path("/assigntrace/v1")
@Produces("application/json;charset-utf-8")
@Consumes("application/json;charset-utf-8")
public class TraceTicketImpl implements ITraceTicket {
	private static final Logger log = LoggerFactory.getLogger(TraceTicketImpl.class);

	private ITicketRepository ticketRepository;

	private BaseInfoRepository baseInfoRepository;

	private WorkflowRepository workflowRepository;

	private QuerySelector querySelector;

	private AttributeBean params;

	@Inject
	public void set(QuerySelector querySelector) {
		this.querySelector = querySelector;
	}

	@Inject
	public void set(AttributeBean params) {
		this.params = params;
	}

	@Inject
	public void set(ITicketRepository ticketRepository) {
		this.ticketRepository = ticketRepository;
	}

	@Inject
	public void set(BaseInfoRepository baseInfoRepository) {
		this.baseInfoRepository = baseInfoRepository;
	}

	@Inject
	public void set(WorkflowRepository workflowRepository) {
		this.workflowRepository = workflowRepository;
	}

	@Override
	public RestResponse<List<TicketVO>> getEntityList(String itsmcode, String entity, SearchListFilter filter) {

		if (log.isDebugEnabled()) {
			log.debug(
					"query tickets parameters : engnieer = {},page = {},limit = {},timeRange = {},status={},project = {},sort = {},includes = {},betweenLng = {},betweenlat = {}",
					filter.getEngineer(), filter.getPage(), filter.getLimit(), filter.getTimeRange(),
					filter.getStatus(), filter.getProject(), filter.getSort(), filter.getIncludes(),
					filter.getBetweenLng(), filter.getBetweenlat());
		}
		RestResponse<List<TicketVO>> rs = null;
		SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		try {
			List<TicketPO> tickets = ticketRepository.getTicketList(itsmcode, filter);
			List<TicketVO> ticketVOs = new ArrayList<>();
			for (TicketPO tpo : tickets) {
				TicketVO tvo = new TicketVO();
				tvo.setTicketid(tpo.getId());// 工单ID
				tvo.setTitle(tpo.getCaption());// 工单标题
				tvo.setRework(tpo.getOthers().getAttributeBean().getAttribute("rework", 0));
				// 工单项目
				ProjectPO project = baseInfoRepository.getProjectById(itsmcode, tpo.getProjectId());
				tvo.setProject(project == null ? "" : project.getName());
				// 客户地址
				String customeraddress = tpo.getOthers().getAttributeBean().getAttribute("customeraddress", "");
				// 实际上门地址
				String address = tpo.getOthers().getAttributeBean().getAttribute("address", "");
				String cityname = tpo.getOthers().getAttributeBean().getAttribute("cityname", "");
				tvo.setCaddress(CommonUtil.isNullOrEmpty(address) ? customeraddress : address);
				//上门地址增加城市名称
				if (CommonUtil.nonNullAndEmpty(cityname)) {
					tvo.setCaddress(cityname + "-" + tvo.getCaddress());
				}
				tvo.setcTime(tpo.getCreateTime());// 创建时间
				tvo.setPosition(tpo.getLongitude() + ":" + tpo.getLatitude());// 经纬度
				// 时效
				TicketSLAPO sla = ticketRepository.getTicketCurrentSLA(itsmcode, tpo.getId());
				if (sla != null) {
					Map<String, Object> status = new HashMap<>();
					String code = sla.getStep().getDescr();
					status.put("code", code);
					Date[] times = new Date[] { sla.getPreWarning(), sla.getOvertime() };
					status.put("value", times);
					tvo.setStatus(status);
				}
				// 响应级别
				String respondLevel = tpo.getOthers().getAttributeBean().getAttribute("respondlevel", "");
				if (!CommonUtil.isNullOrEmpty(respondLevel)) {
					respondLevel = StringUtils.substringAfterLast(respondLevel, "*");
					tvo.setRespondLevel(respondLevel + "h");
				}
				// 获取活动工单当前节点的操作图标和文字描述
				if (TicketStatus.get(filter.getStatus()) == TicketStatus.INEXCUTION) {
					try {
						// 获取工单当前流程的活动节点
						TicketProcessPO ticketProcess = workflowRepository.getRuningTicketProcess(itsmcode,
								tpo.getId());
						List<ProcessActivityPO> activites = workflowRepository
								.getProcessActivities(ticketProcess.getProcessId());
						ticketProcess.setActivites(activites);
						ProcessActivityPO activity = ticketProcess.getCurrentActivity();
						Map<String, Object> shorcut = new HashMap<>();
						if (!Objects.isNull(activity)) {
							shorcut.put("name", activity.getActivityName());
							shorcut.put("icon", activity.getOpicoUrl());
							shorcut.put("link", activity.getActivityId());
							tvo.setShortcut(shorcut);
							// 文本描述
							String[] description = new String[2];
							ProcessActivityPO prevActivity = null;
							for (ProcessActivityPO aty : activites) {
								if (aty.getSortForApp() == (activity.getSortForApp() - 1) && aty.getShowForApp()) {
									prevActivity = aty;
									break;
								}
							}
							description[0] = Objects.isNull(prevActivity) ? "" : prevActivity.getActivityName();
							description[1] = activity.getActivityName();
							tvo.setDescription(description);
							//处于已完成待评价状态的活动工单 列表中 时效显示：关单逾期时间 =  实际完成时间+30天
							if (activity.getActivityKey().equals("customerFeedback")) {
							    Map<String, Object> status = new HashMap<>();
			                    status.put("code", "关单逾期时间");
			                    //计算关单逾期时间
		                        Calendar calendar = Calendar.getInstance();
		                        calendar.setTime(tpo.getUpdateTime());
		                        calendar.add(Calendar.DATE, 30);
		                        Date[] times = new Date[] { null, calendar.getTime() };
                                status.put("value", times);
                                tvo.setStatus(status);
							}
						}
					} catch (Exception exp) {
						log.warn("ticket {} get shortcut icon error!", tpo.getId());
					}
				}
				// 工单优先级
				TicketPriority ticketPriority = TicketPriority.get(tpo.getPriority());
				if (!Objects.isNull(ticketPriority))
					tvo.setPriority(ticketPriority.getDescr());
				// 抢单倒计时
				if (TicketPolicy.get(tpo.getPolicy()) == TicketPolicy.GRAB) {
					Calendar calendar = Calendar.getInstance();
					calendar.setTime(tpo.getStartTime());
					List<Date> timers = new ArrayList<>();
					int groups = params.getAttribute("group.number", 1);
					String retryInterval = System.getProperty("RETRY_INTERVAL", "10");
					for (int i = 0; i < groups; i++) {
						calendar.add(Calendar.MINUTE, Integer.valueOf(retryInterval));
						timers.add(calendar.getTime());
					}
					tvo.setTimers(timers);
				}
				// 历史工单 增加工单状态 结束时间 工单类型 客户评价结果
				if (TicketStatus.get(filter.getStatus()) == TicketStatus.CLOSED || TicketStatus.get(filter.getStatus()) == TicketStatus.BREAK) {
					Object appStatus = tpo.getOthers().getAttributeBean().get("appstatus");
					if (Objects.nonNull(appStatus)) {
						tvo.setAppstatus(AppStatus.values()[Integer.parseInt(appStatus.toString())].getDescr());
					}
					Object evaluate = tpo.getOthers().getAttributeBean().get("evaluateresults");
					// 评价
					if (Objects.nonNull(evaluate)) {
						EvaluateResults er = EvaluateResults.values()[Integer.parseInt(evaluate.toString())];
						tvo.setEvaluate(er.getDescr());
					}
					// 结束时间
					String overtime = tpo.getOthers().getAttributeBean().getAttribute("actualcompletetime", "");
					if (CommonUtil.nonNullAndEmpty(overtime)) {
						tvo.setOvertime(format.parse(overtime));
					}
					else {
					    tvo.setOvertime(tpo.getUpdateTime());
					}
					// 工单类型
					Integer tickettype = tpo.getOthers().getAttributeBean().getAttribute("tickettype", 1);
					if (Objects.nonNull(tickettype)) {
						TicketType type = TicketType.values()[tickettype];
						tvo.setTickettype(type.getDescr());
					}
	                tvo.setState(tpo.getStatus());
				}
				//工单更新标识
				tvo.setSurveynotechanged(tpo.getOthers().getAttributeBean().getAttribute("surveynotechanged", 0));
				tvo.setChangenottobeview(tpo.getOthers().getAttributeBean().getAttribute("changenottobeview", 0));
				ticketVOs.add(tvo);
			}
			rs = new RestResponse<List<TicketVO>>(0, "OK", ticketVOs);
		} catch (Exception exp) {
			TraceableException.writeLog(ErrorCode.COMM_ERROR, "get ticket list error", exp);
		}
		return rs;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.lenovo.lmrp.api.assigntrace.ITraceTicket#getEntityList(java.lang.
	 * String, java.lang.String, java.lang.String, java.lang.String)
	 */
	@Override
	public <T> RestResponse<T> getEntityDetail(String itsmcode, String entity, String entityid, String includes) {
		try (ICommonDAO dao = ADaoFactory.getDefault().createDAO(itsmcode)) {
			Class<T> tClass = (Class<T>) QueryEntity.valueOf(entity.toUpperCase()).getC();
			T o = dao.get(tClass, entityid);
			return new RestResponse<>(0, "OK", o);
		} catch (Exception e) {
			throw new TraceableException(ErrorCode.DB_QUERY_FAILED, e);
		}
	}

	/**
	 * @see com.lenovo.lmrp.api.assigntrace.ITraceTicket#updateTicket(java.lang.String,
	 *      java.lang.String, java.lang.String, java.util.Map)
	 */
	@Override
	public RestResponse<String> updateTicket(String itsmcode, String ticketid, String action,
			Map<String, String> fields) {
		RestResponse<String> response;
		try {
			TicketProcessBO processBO = workflowRepository.createTicketProcessBO(itsmcode, ticketid, true);
			// 执行工作流
			ChangedTicketVO vo = new ChangedTicketVO();
			vo.setFields(fields);
			vo.setAction(action);
			vo.setTicketid(ticketid);
			processBO.triggerWorkflow(vo);

			// 获取下一步工作流节点，回传APP，用来请求H5页面
			ProcessActivityPO nextActivity = processBO.getNextActivity();
			if (Objects.isNull(nextActivity)) {
				response = new RestResponse<String>(0, "ok", null);
			} else {
				response = new RestResponse<String>(0, "ok", nextActivity.getActivityId());
			}
			return response;
		} catch (Exception exp) {
		    log.error("trace error when update ticket {},action {}",ticketid,action);
			throw new TraceableException(ErrorCode.DB_TRANS_FAILED, exp);
		}
	}

	/**
	 * @see com.lenovo.lmrp.api.assigntrace.ITraceTicket#uploadAttachment(java.lang.String,
	 *      java.lang.String, com.lenovo.lmrp.api.model.view.AttachmentVO)
	 */
	@Override
	public void uploadAttachment(String itsmcode, String ticketid, AttachmentVO attachmentVO) {
		// TODO Auto-generated method stub

	}

	/**
	 * @see com.lenovo.lmrp.api.assigntrace.ITraceTicket#ticketsStatistics(java.lang.String,
	 *      java.lang.String, java.lang.String, java.lang.String)
	 */
	@Override
	public RestResponse<TicketStatistics> ticketsStatistics(String itsmcode, String conditions, String groupby,
			String orderby) {
		// TODO Auto-generated method stub
		return null;
	}

	/**
	 * @see com.lenovo.lmrp.api.assigntrace.ITraceTicket#getTicketCost(java.lang.String,
	 *      java.lang.String)
	 */
	@Override
	public RestResponse<TicketCost> getTicketCost(String itsmcode, String ticketid) {
		// TODO Auto-generated method stub
		return null;
	}

	/**
	 * @see com.lenovo.lmrp.api.assigntrace.ITraceTicket#getEngineersBill(java.lang.String,
	 *      java.lang.String)
	 */
	@Override
	public Object getEngineersBill(String itsmcode, String engineerid) {
		// TODO Auto-generated method stub
		return null;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.lenovo.lmrp.api.assigntrace.ITraceTicket#getEntityTotal(java.lang.
	 * String, java.lang.String, java.lang.String)
	 */
	@SuppressWarnings("unchecked")
	@Override
	public <T> RestResponse<T> getEntityTotal(String itsmcode, String entity, String engnieer) {
	    
	    TicketTotalVO total = ticketRepository.getAssigningTicketsByEngineer(itsmcode, engnieer);
		if(total == null) {
		    total = new TicketTotalVO();
		}
	    return new RestResponse<T>(0, "ok", (T) total);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.lenovo.lmrp.api.assigntrace.ITraceTicket#getGrabResult(java.lang.
	 * String, java.lang.String)
	 */
	@Override
	public RestResponse<Object> getGrabResult(String itsmcode, String engineerid, String ticketid) {
        RestResponse<Object> response = null;
        try (ICommonDAO dao = ADaoFactory.getDefault().createDAO(itsmcode)) {
            TicketPO ticketPO = dao.get(TicketPO.class, ticketid);
            Map<String, Object> result = new HashMap<>();
            
            // 查询工作流当前状态
            TicketProcessBO ticketProcessBO = workflowRepository.createTicketProcessBO(itsmcode, ticketid, true);
            ProcessActivityPO currActivity = ticketProcessBO.getCurrentActivity();
            if (Objects.isNull(currActivity))
                throw new IllegalArgumentException("work flow has stopped for tiecket " + ticketid);
            
            if (log.isDebugEnabled())
                log.debug("engineer {} query ticket {} grab result, now assignee is {} ", 
                            engineerid, ticketid, ticketPO.getAssignee());
            
            // 如果工单执行人为空，表明抢单进行中
            if (CommonUtil.isNullOrEmpty(ticketPO.getAssignee())) {
                result.put("success", 2);
                response = new RestResponse<Object>(0, "抢单中", result);
            }
            else {
                // 如果工单执行人与当前查询状态的用户一致，表明该工程师抢单成功
                if (ticketPO.getAssignee().equals(engineerid)) {
                    // 抢单成功
                    if (currActivity.getActivityKey().equalsIgnoreCase(TicketAction.APPOINT.name())) {
                        result.put("success", 1);
                        result.put("link", currActivity.getActivityId());
                        response = new RestResponse<Object>(0, "抢单成功", result);
                    }
                    else {// 防止抢单流程没有彻底完成
                        result.put("success", 2);
                        response = new RestResponse<Object>(0, "抢单中", result);
                    }
                }
                else { // 没抢到工单
                    result.put("success", 0);
                    response = new RestResponse<Object>(0, "抢单失败", result);
                }
            }
            log.debug("ticket {} grab result {}", ticketid, response.getReason());
        }
        catch (Exception exp) {
            throw new TraceableException(ErrorCode.DB_QUERY_FAILED, exp.getMessage());
        }
        return response;
	}

	/**
	 * 获取退单中的cc成员列表
	 */
	@Override
	public RestResponse<List<Map<String, String>>> getProjectEngineers(String itsmcode, String ticketid) {
		log.debug("itsmcode {} ticket {}", itsmcode, ticketid);
		List<Map<String, String>> projectExtense = querySelector.getProjectExtense(itsmcode, ticketid);
		return new RestResponse<List<Map<String, String>>>(0, "ok", projectExtense);
	}

}
